package com.ljqc.sbom.management.service.feignClient.impl;

import com.alibaba.fastjson.JSONObject;
import com.ljqc.sbom.management.domain.Vulnerability;
import com.ljqc.sbom.management.service.feignClient.KbApiClientService;
import com.ljqc.sbom.management.service.feignClient.KbApiService;

import com.ljqc.sbom.management.service.feignClient.dto.DataVulInfo;
import com.ljqc.sbom.management.service.feignClient.dto.ListByLjVulIdsReqVO;
import com.ljqc.sbom.management.util.PageResultDto;
import com.ljqc.sbom.management.util.PageResultUtils;
import com.ljqc.sbom.management.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
public class KbApiServiceImpl implements KbApiService {
    @Autowired
    private KbApiClientService kbApiClientService;



    @Override
    public List<Vulnerability> getVulList(List<String> vulIdList) {
        List<Vulnerability> vulList = new ArrayList<>();
        if(CollectionUtils.isEmpty(vulIdList)){
            return vulList;
        }
        PageResultDto pageResult = PageResultUtils.getPageResult(1, 100, vulIdList);
        for(int i=1;i<=pageResult.getTotalPages();i++) {
            PageResultDto tempPage = PageResultUtils.getPageResult(i, 100, vulIdList);
            ListByLjVulIdsReqVO vo = new ListByLjVulIdsReqVO();
            vo.setVulIds(tempPage.getRecords());
            Result<List<DataVulInfo>> listResult = kbApiClientService.listByLjVulIds(vo);
            List<DataVulInfo> data = listResult.getData();
            if(!CollectionUtils.isEmpty(data)){
                List<Vulnerability> vulListPage = convertData(data);
                vulList.addAll(vulListPage);
            }
        }
        return vulList;
    }

    private List<Vulnerability> convertData(List<DataVulInfo> data){
        List<Vulnerability> list = new ArrayList<>();
        data.forEach(x->{
            Vulnerability vul = new Vulnerability();
            vul.setCveId(x.getCveId());
            vul.setLjVulId(x.getLjVulId());
            vul.setPkgVulId(StringUtils.isEmpty(x.getPkgVulId())?x.getLjVulId():x.getPkgVulId());
//            vul.setNoCveId(x.getn);
            vul.setDataSource(x.getDataSource());
            vul.setCnnvdId(x.getCnnvdId());
            vul.setCnnvdTitle(x.getCnnvdTitle());
            vul.setVulnTitleCn(x.getVulTitleCn());
            vul.setVulnTitleEn(x.getVulTitleEn());
            vul.setVulnSeverityCn(x.getVulSeverityCn());
            vul.setVulnSeverityEn(x.getVulSeverityCn());
            vul.setVulnSolutionCn(x.getVulSolutionCn());
            vul.setVulnSolutionEn(x.getVulSolutionEn());
            vul.setCvssV2(getFormatCVSS(x.getCvssV2(),x.getCvss2BaseScore(),2));
            vul.setCvssV3(getFormatCVSS(x.getCvssV3(),x.getCvss3BaseScore(),3));
            vul.setVulnDescribeCn(x.getVulDescribeCn());
            vul.setVulnDescribeEn(x.getVulDescribeEn());
            String url = x.getUrl();
            if(StringUtils.isEmpty(url)){
                vul.setVulnRefs("[]");
            }else{
                vul.setVulnRefs(JSONObject.toJSONString(Arrays.asList(url.split(","))));
            }
            vul.setVulnPublished(x.getVulPublished());
            vul.setCwe(x.getVulTypeEn());
//            vul.setCweTitleCn(x.getVulTitleCn());
//            vul.setCweTitleEn(x.getVulTitleCn());
            vul.setVulnTypeCn(x.getVulTypeCn());
            vul.setVulnTypeEn(x.getVulTypeEn());
            vul.setExpLevel(StringUtils.isEmpty(x.getExpLevel())?0:Integer.valueOf(x.getExpLevel()));
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(vul.getCvssV3())){
                JSONObject jsonObject = JSONObject.parseObject(vul.getCvssV3());
                vul.setAcessTypeCn(Optional.ofNullable(jsonObject.getString("AV")).orElse(""));
                vul.setAcessTypeEn(vul.getAcessTypeCn());
            }else if (org.apache.commons.lang3.StringUtils.isNotEmpty(vul.getCvssV2())){
                JSONObject jsonObject = JSONObject.parseObject(vul.getCvssV3());
                vul.setAcessTypeCn(Optional.ofNullable(jsonObject.getString("AV")).orElse(""));
                vul.setAcessTypeEn(vul.getAcessTypeCn());
            }
            vul.setCweList(x.getCweVOList());
            list.add(vul);
        });
        return list;
    }


    private static String getFormatCVSS(String cvss, BigDecimal baseScore, int type){//2-cvss2, 3-cvss3
        JSONObject jsonObject = new JSONObject();
        if(StringUtils.isEmpty(cvss)){
            return JSONObject.toJSONString(jsonObject);
        }
        String[] split = cvss.split("/");
        for (String keyValue: split) {
            String[] split1 = keyValue.split(":");
            String key  =String.valueOf(split1[0]);
            String value =String.valueOf(split1[1]);
            if("AV".equals(key)){
                jsonObject.put(key,formatCVSS_AV(value));
            }else if("AC".equals(key)){
                jsonObject.put(key,formatCVSS_AC(value));
            }else if("Au".equals(key)){
                jsonObject.put(key,formatCVSS_Au(value));
            }else if("UI".equals(key)){
                jsonObject.put(key,formatCVSS_UI(value));
            }else if("S".equals(key)){
                jsonObject.put(key,formatCVSS_S(value));
            }else if(type==2 && ("C".equals(key) || "I".equals(key) || "A".equals(key))){
                jsonObject.put(key,formatCVss2_ICA(value));
            }else if(type==3 && ("C".equals(key) || "I".equals(key) || "A".equals(key) || "PR".equals(key))){
                jsonObject.put(key,formatCVss3_ICA_PR(value));
            }
            jsonObject.put("baseScore",baseScore);
        }
        return JSONObject.toJSONString(jsonObject);
    }

    private static String formatCVSS_AV(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NETWORK";
            case "A":
                return "ADJACENT_NETWORK";
            case "L":
                return "LOCAL";
            case "P":
                return "PHYSICAL";
        }
        return "";
    }

    private static String formatCVSS_AC(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "L":
                return "LOW";
            case "M":
                return "MEDIUM";
            case "H":
                return "HIGH";
        }
        return "";
    }

    private static String formatCVSS_UI(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "R":
                return "REQUIRED";
        }
        return "";
    }

    private static String formatCVSS_Au(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "M":
                return "MULTIPLE";
            case "S":
                return "SINGLE";
        }
        return "";
    }

    private static String formatCVSS_S(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "U":
                return "UNCHANGED";
            case "C":
                return "CHANGED";
        }
        return "";
    }

    private static String formatCVss2_ICA(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "P":
                return "PARTIAL";
            case "C":
                return "COMPLETE";
        }
        return "";
    }

    private static String formatCVss3_ICA_PR(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "L":
                return "LOW";
            case "H":
                return "HIGH";
        }
        return "";
    }


}
